package scene.map 
{
	import event.CommEvent;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.utils.Dictionary;
	import log.Log;
	import utils.clientConst;
	/**
	 * ...
	 * @author carlor
	 */
	public class Map extends Sprite
	{
		protected var _mapData	 : MapData;				//
		protected var _tileColNum: int;					// 地图由多少tile拼接而成
		protected var _tileRowNum: int;				
		protected var _loadedTile: int;

		protected var _tileDatas : Array;		
		protected var _cellDatas : Array;				// 地图可进入点、不可进入点、遮挡等数据
		protected var _tileLayer : Sprite;
		protected var _cellLayer : Sprite;
		protected var _destCells : Object;
		protected var _moveCells : Array;
		protected var _attackCells: Array;
		protected var _showMovecell: Boolean;
		protected var _lineLayer : Sprite;		
		
		// 视点 
		protected var _viewPoint : Point;				
		protected var _viewRect  : Rectangle;
		protected var _viewTiles : Dictionary;
	
		public function Map(mapData: MapData, cellData: Array) 
		{
			_mapData = mapData;
			_tileColNum = Math.ceil(mapData.mapWidth * clientConst.CELLWIDTH / clientConst.TILEWIDHT);
			_tileRowNum = Math.ceil(mapData.mapHeight * clientConst.CELLHEIGHT / clientConst.TILEHEIGHT);
			_tileDatas = new Array();
			_cellDatas = cellData;
			_loadedTile= 0;
			
			_tileLayer = new Sprite();
			_tileLayer.cacheAsBitmap = true;
			_tileLayer.mouseEnabled  = false;
			_tileLayer.mouseChildren = false;
			this.addChild(_tileLayer);
			
			_cellLayer = new Sprite();
			_cellLayer.cacheAsBitmap = true;
			_cellLayer.mouseEnabled  = false;
			_cellLayer.mouseChildren = false;
			this.addChild(_cellLayer);

			_lineLayer = new Sprite();
			_lineLayer.cacheAsBitmap= true;
			_lineLayer.mouseEnabled = false;
			_lineLayer.mouseChildren= false;
			this.addChild(_lineLayer);	
			
			_viewPoint = new Point();
			_viewRect  = new Rectangle();
			_viewTiles = new Dictionary();
			_destCells = new Object();

			this.init();
			this.addEventListener(CommEvent.LOADED_COMPLETE, onAddMapTile);
			this.cacheAsBitmap = true;	
		}
		
		private function clearActionCell(cell: Array): void
		{
			if (! cell) return;
			
			while (cell.length > 0) {
				var obj: Object = cell.pop();
				obj = null;
			}
			cell = null;
		}
		
		public function dispose(): void
		{
			this.removeEventListener(CommEvent.LOADED_COMPLETE, onAddMapTile);
			
			_lineLayer = null;
			_cellLayer = null;
			_tileLayer = null;
			_mapData.dispose();
			_mapData = null;
			
			var list: Array = [];
			var tile: Object;
			for (tile in _viewTiles) {
				list.push(tile);
			}
			while (list.length > 0) {
				tile = list.pop();
				_viewTiles[tile].bitmapData = null;
				_viewTiles[tile] = null;
				delete _viewTiles[tile];	
				tile = null;
			}
			_viewTiles = null;
			
			while (_tileDatas.length > 0) {
				var data: Array = _tileDatas.pop();
				while (data.length > 0) {
					var mapTile: MapTile = data.pop();
					mapTile.dispose();
					mapTile = null;
				}
				data = null;
			}
			
			_cellDatas = null;
			_viewPoint = null;
			_viewRect  = null;
		
			for each (var p: Point in _destCells) {
				p = null;
			}
			_destCells = null;
			clearActionCell(_moveCells);
			clearActionCell(_attackCells);
		}
		
		private function addZero(value: Number, bits: int=2): String
		{
			var ret: String = String(value);
			while (ret.length < bits) ret = "0" + ret;
			return ret;
		}
		
		protected function init(): void
		{
			// int maptiles
			for (var i: int = 0; i < _tileRowNum; i++) {
				var rowTiles: Array = new Array();
				for (var j: int = 0; j < _tileColNum; j++) {
					var r: Rectangle = new Rectangle(j * clientConst.TILEWIDHT, i * clientConst.TILEHEIGHT, clientConst.TILEWIDHT, clientConst.TILEHEIGHT);
					if (j == _tileColNum - 1)
						r.width = _mapData.mapWidth * clientConst.CELLWIDTH - (j - 1) * clientConst.TILEWIDHT;
					if (i == _tileRowNum - 1)
						r.height = _mapData.mapHeight * clientConst.CELLHEIGHT - (i - 1) * clientConst.TILEHEIGHT;
					var mapTile: MapTile = new MapTile(this, Engine.settingPath + "map" + "\\" + _mapData.mapId + "\\" + "tile\\" + _mapData.mapId + "_" + addZero(i) + "x" + addZero(j) + ".jpg", j, i, r);
					rowTiles.push(mapTile);
					mapTile.loadImage();
					_viewTiles[mapTile] = new Bitmap();
					this._tileLayer.addChild(_viewTiles[mapTile]);
				}
				_tileDatas.push(rowTiles);
			}
		}
		
		public function update(curTime: int): void
		{
			
		}
		
		public function clearActionCells(): void
		{
			clearActionCell(_moveCells);
			clearActionCell(_attackCells);
			for (var key: String in _destCells) {
				_destCells[key] = null;
				delete _destCells[key];
			}
			drawActionCells();
		}
		
		public function setMoveCell(cells: Array): void
		{
			clearActionCell(_moveCells);
			
			this._moveCells = cells;
			_showMovecell = cells != null;
			drawActionCells();
		}
		
		public function setAttackCell(cells: Array): void
		{
			clearActionCell(_attackCells);
			
			this._attackCells = cells;
			_showMovecell = cells == null;
			drawActionCells();
		}
		
		public function addDestCells(p: Point): void
		{
			var key: int = getKey(p.x, p.y);
			if (this._destCells[key]) return;
			this._destCells[key] = p;
			drawActionCells();
		}
		
		private function getKey(x: int, y: int): int
		{
			return y * _mapData.mapWidth + x;
		}
		
		public function deleteDestCells(p: Point): void
		{
			var key: int = getKey(p.x, p.y);
			if (! this._destCells[key]) return;
			this._destCells[key] = null;
			delete this._destCells[key];
			drawActionCells();
		}
		
		public function inMoveCell(pos: Point): Boolean
		{
			if (! _moveCells) return false;
			
			var len: int = _moveCells.length;
			for (var i: int = 0; i < len; i++) {
				if (pos.x == _moveCells[i].x && pos.y == _moveCells[i].y)
					return true;
			}
			return false;
		}
		
		public function inAttackCell(pos: Point): Boolean
		{
			if (! _attackCells) return false;
			
			var len: int = _attackCells.length;
			for (var i: int = 0; i < len; i++) {
				if (pos.x == _attackCells[i].x && pos.y == _attackCells[i].y)
					return true;
			}
			
			return false;
		}
		
		///////////////// image
		protected function drawActionCells(): void
		{
			var i: int;
			var p: Point;
			this._cellLayer.graphics.clear();
			
			if (_moveCells != null && _showMovecell) {
				this._cellLayer.graphics.beginFill(0x009900, 0.5);
				for (i  = 0; i < _moveCells.length; i++) {
					p = this._moveCells[i];
					this._cellLayer.graphics.drawRoundRectComplex(p.x * clientConst.CELLWIDTH - _viewRect.left, p.y * clientConst.CELLHEIGHT - _viewRect.top, clientConst.CELLWIDTH, clientConst.CELLHEIGHT, 10, 10, 10, 10);
				}	
			}
			
			if (_attackCells != null && !_showMovecell) {
				this._cellLayer.graphics.beginFill(0x990000, 0.5);
				for (i = 0; i < _attackCells.length; i++) {
					p = this._attackCells[i];
					this._cellLayer.graphics.drawRoundRectComplex(p.x * clientConst.CELLWIDTH - _viewRect.left, p.y * clientConst.CELLHEIGHT - _viewRect.top, clientConst.CELLWIDTH, clientConst.CELLHEIGHT, 10, 10, 10, 10);
				}
			}
			
			this._cellLayer.graphics.beginFill(0xffff00, 0.5);
			for each (p in this._destCells) {
				this._cellLayer.graphics.drawRoundRectComplex(p.x * clientConst.CELLWIDTH - _viewRect.left, p.y * clientConst.CELLHEIGHT - _viewRect.top, clientConst.CELLWIDTH, clientConst.CELLHEIGHT, 10, 10, 10, 10);
			}
			
			this._cellLayer.graphics.endFill();
		}
		
		private function drawLines(): void
		{
			while (this._lineLayer.numChildren > 0) {
				var child: DisplayObject = this._lineLayer.removeChildAt(0);
				child = null;
			}
			this._lineLayer.graphics.clear();
			
			this._lineLayer.graphics.lineStyle(1, 0x888888);
			for (var i: int = _viewRect.left; i < _viewRect.right; i++) {
				if (i % clientConst.CELLWIDTH != 0) continue;
				
				if (i % clientConst.TILEWIDHT == 0) {
					this._lineLayer.graphics.lineStyle(1, 0xeeeeee);
				}
				else
					this._lineLayer.graphics.lineStyle(1, 0x888888);
				this._lineLayer.graphics.moveTo(i-_viewRect.left, 0);
				this._lineLayer.graphics.lineTo(i-_viewRect.left, _viewRect.bottom-_viewRect.top);					
			}
			for (i = _viewRect.top; i < _viewRect.bottom; i++) {
				if (i % clientConst.CELLHEIGHT != 0) continue;
				
				if (i % clientConst.TILEHEIGHT == 0) {
					this._lineLayer.graphics.lineStyle(1, 0xeeeeee);
				}
				else
					this._lineLayer.graphics.lineStyle(1, 0x888888);			
				this._lineLayer.graphics.moveTo(0, i - _viewRect.top);
				this._lineLayer.graphics.lineTo(_viewRect.right - _viewRect.left, i - _viewRect.top);
			}
		}
		
		
		protected function onAddMapTile(e: CommEvent): void
		{
			var mapTile: MapTile = e.getData("mapTile") as MapTile;
			if (! mapTile.image || ! mapTile.image.data) return;
			if (_viewTiles[mapTile]) {
				_viewTiles[mapTile].bitmapData = mapTile.image.data;
				if (++_loadedTile >= _tileColNum * _tileRowNum) {
					this.dispatchEvent(new CommEvent(CommEvent.MAPLOADED_COMPLETE));
				}
			}
		}
		
		protected function deleteMapTile(rect: Rectangle): void
		{
			for each (var obj: Object in _viewTiles) {
				(obj as Bitmap).visible = false;
			}
		}
		
		protected function addMapTile(rect: Rectangle): void
		{
			for (var i: int = rect.top; i < rect.bottom; i++) {
				for (var j: int = rect.left; j < rect.right; j++) {
					_viewTiles[_tileDatas[i][j]].x = _tileDatas[i][j].rect.left - _viewRect.left;
					_viewTiles[_tileDatas[i][j]].y = _tileDatas[i][j].rect.top - _viewRect.top;
					_viewTiles[_tileDatas[i][j]].visible = true;
				}
			}			
		}
		
		protected function updateMapTile(rect: Rectangle): void
		{
			this.deleteMapTile(rect);
			this.addMapTile(rect);
		}
		
		////////////// viewpoint
		public function setViewPoint(p: Point, disEvent: Boolean = true): void
		{
			_viewPoint.x = p.x <= 0 ? 0 : (p.x > _mapData.mapWidth ? _mapData.mapWidth * clientConst.CELLWIDTH: p.x*clientConst.CELLWIDTH);
			_viewPoint.y = p.y <= 0 ? 0 : (p.y > _mapData.mapHeight ? _mapData.mapHeight * clientConst.CELLHEIGHT: p.y*clientConst.CELLHEIGHT);
			
			setViewRect(disEvent);
		}
		
		public function setViewPointX(px: int, py: int, disEvent: Boolean = true ): void
		{
			_viewPoint.x = px <= 0 ? 0 : (px > _mapData.mapWidth * clientConst.CELLWIDTH ? _mapData.mapWidth * clientConst.CELLWIDTH : px);
			_viewPoint.y = py <= 0 ? 0 : (py > _mapData.mapHeight * clientConst.CELLHEIGHT ? _mapData.mapHeight * clientConst.CELLHEIGHT : py);
			setViewRect(disEvent);
		}
		
		public function updateViewPoint(mx: int, my: int, disEvent: Boolean = true): void
		{
			var px: int = _viewPoint.x + mx;
			var py: int = _viewPoint.y + my;
			setViewPointX(px, py, disEvent);
		}
		
		protected function getContainerRect(): Rectangle
		{
			return new Rectangle(0, 0, Engine.mainStage.stageWidth, Engine.mainStage.stageHeight);
		}

		public function setViewRect(disEvent: Boolean = true): void
		{
		
			var sceneCenter: Point = _viewPoint;
			var rect: Rectangle = getContainerRect();
			var a: int = _viewRect.left;
			_viewRect.left   = Math.floor(Math.max(sceneCenter.x - rect.right / 2, 0));
			_viewRect.top    = Math.floor(Math.max(sceneCenter.y - rect.bottom / 2, 0));
			_viewRect.right  = Math.ceil(Math.min(sceneCenter.x + rect.right / 2, _mapData.mapWidth*clientConst.CELLWIDTH));
			_viewRect.bottom = Math.ceil(Math.min(sceneCenter.y + rect.bottom / 2, _mapData.mapHeight * clientConst.CELLHEIGHT));
			
			if (_viewRect.right - _viewRect.left < rect.right)
				_viewRect.right = Math.ceil(Math.min(_viewRect.left + rect.right, _mapData.mapWidth * clientConst.CELLWIDTH));
			if (_viewRect.bottom - _viewRect.top < rect.bottom)
				_viewRect.bottom = Math.ceil(Math.min(_viewRect.top + rect.bottom, _mapData.mapHeight * clientConst.CELLHEIGHT));
			if (_viewRect.right - _viewRect.left < rect.width)
				_viewRect.left = Math.max(_viewRect.right - rect.width, 0);
			if (_viewRect.bottom - _viewRect.top < rect.height)
				_viewRect.top = Math.max(_viewRect.bottom - rect.height, 0);	
			var leftIndex  : int = Math.floor(_viewRect.left / clientConst.TILEWIDHT);
			var rightIndex : int = Math.ceil(_viewRect.right / clientConst.TILEWIDHT);
			var topIndex   : int = Math.floor(_viewRect.top / clientConst.TILEHEIGHT);
			var bottomIndex: int = Math.ceil(_viewRect.bottom / clientConst.TILEHEIGHT);			

			this.updateMapTile(new Rectangle(leftIndex, topIndex, rightIndex - leftIndex, bottomIndex - topIndex));
			drawActionCells();
			drawLines();
			if (disEvent)
				this.dispatchEvent(new CommEvent(CommEvent.MAP_VIEWCHANGE));
		}
		
		public function screenPos2MapPos(p: Point): Point
		{
			return new Point(Math.floor((p.x + _viewRect.left) / clientConst.CELLWIDTH), Math.floor((p.y + _viewRect.top) / clientConst.CELLHEIGHT));
		}
		
		public function mapPos2ScreenPos(p: Point): Point
		{
			return new Point(p.x * clientConst.CELLWIDTH - _viewRect.left, p.y * clientConst.CELLHEIGHT - _viewRect.top);
		}	
		
		public function scenePos2ScreenPos(p: Point): Point
		{
			return new Point(p.x - _viewRect.left, p.y - _viewRect.top);
		}
		
		public function getViewPoint(): Point
		{
			return _viewPoint;
		}
		
		public function getViewRect(): Rectangle
		{
			return _viewRect;
		}
		
		public function get mapData(): MapData
		{
			return _mapData;
		}
		
		public function get tileColNum(): int
		{
			return _tileColNum;
		}
		
		public function get tileRowNum(): int
		{
			return _tileRowNum;
		}
		
		public function get cellData(): Array
		{
			return _cellDatas;
		}
		
		public function get isMoveState(): Boolean
		{
			return _showMovecell;
		}
	}

}